﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Kugar.Core.ExtMethod;
using Kugar.Core.Web;
using Kugar.Core.Web.Authentications;
using Kugar.Web.Wechat.Entities;
using Kugar.Web.Wechat.Enums;
using Kugar.Web.Wechat.MP;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Session;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Senparc.CO2NET;
using Senparc.CO2NET.RegisterServices;
using Senparc.Weixin;
using Senparc.Weixin.Entities;
using Senparc.Weixin.MP;
using Senparc.Weixin.MP.AdvancedAPIs;
using Senparc.Weixin.RegisterServices;
using ILogger = Kugar.Core.Log.ILogger;
using LogLevel = Kugar.Core.Log.LogLevel;

namespace Kugar.Web.Wechat
{
    public class WechatMPOAuthOption
    {
        public string Scheme { set; get; }

        public WechatUserOAuth DefaultUser { set; get;}

        public string EncKey { set; get; }

        /// <summary>
        /// token校验成功后,触发该回调,如果回调中,需要登录失败,调用context的Fail函数,会触发OnChallenge回调
        /// </summary>
        public Func<TokenValidatedContext, Task> OnTokenValidated { set; get; }

        /// <summary>
        /// 登录失败时,触发该回调,如需要触发跳转,使用context.Response.Redirect,后使用context.HandleResponse()中止后续处理
        /// </summary>
        public Func<JwtBearerChallengeContext, Task> OnChallenge { set; get; }
    }

    public static class GlobalConfigurationHelper
    {
        public static void UseWechatOAuth(this IServiceCollection services, IConfiguration configuration,string scheme, WechatMPOAuthOption option)
        {
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

            services.AddSenparcGlobalServices(configuration)//Senparc.CO2NET 全局注册
                .AddSenparcWeixinServices(configuration);//Senparc.Weixin 注册（如果使用Senparc.Weixin SDK则添加）
            
            System.Net.ServicePointManager.SecurityProtocol =
                SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

            services.AddSingleton<IWechatMP>(WechatApi.Default.MP);

            services.AddAuthentication().AddWebJWT(scheme, new WebJWTOption()
            {
                Audience = "mp",
                Issuer = "wechat",
                LoginUrl = "/",
                OnTokenValidated = async (context) =>
                {
                    var handler =
                        (IMPOAuthWithSchemeHandler)context.HttpContext.RequestServices.GetService(
                            typeof(IMPOAuthWithSchemeHandler));

                    var endPoint = (IEndpointFeature) context.HttpContext.Features.Get<IEndpointFeature>();

                    var attr = endPoint.Endpoint.Metadata.GetMetadata<WechatMPOAuthSchemeAttribute2>();

                    var mp =await handler.MPGetter(scheme);

                    var scope=context.Principal.FindFirst("wechat_scope")?.Value.ToInt(-1);
                    var appID= context.Principal.FindFirst("wechat_appID")?.Value.ToStringEx();
                     
                    if (scope < (int)attr.Scope || appID!=mp.appID)
                    {
                        context.Fail("微信授权无效");
                    }
                    else
                    {
                        context.Success();

                        if (option.OnTokenValidated!=null)
                        {
                            await option.OnTokenValidated(context);
                        }
                    }

                    
                },
                OnChallenge = async (context) =>
                {
                    if (option.OnChallenge != null)
                    {
                        await option.OnChallenge(context);
                    }

                    if (!context.Handled)
                    {
                        var handler =
                            (IMPOAuthWithSchemeHandler)context.HttpContext.RequestServices.GetService(
                                typeof(IMPOAuthWithSchemeHandler));
                        //Microsoft.AspNetCore.Http.Features.IEndpointFeature.Endpoint ={ Kugar.AdminLte.Core.Test.Controllers.HomeController.Index(Kugar.AdminLte.Core.Test)}

                        var mp = await handler.MPGetter(context.Scheme.Name);

                        var endPoint = (IEndpointFeature)context.HttpContext.Features.Get<IEndpointFeature>();

                        var attr = endPoint.Endpoint.Metadata.GetMetadata<WechatMPOAuthSchemeAttribute2>();

                        var guid = Guid.NewGuid().ToString("N");

                        var url = OAuthApi.GetAuthorizeUrl(mp.appID, "/Core/MPCallback/Callback", guid, attr.Scope,
                            "code");

                        var json = new JObject()
                        {
                            ["BackUrl"] = context.HttpContext.Request.GetDisplayUrl(),
                            ["Scope"] = (int)attr.Scope,
                            ["AppID"] = mp.appID,
                            ["AppSecret"] = mp.appSecret,
                        };

                        context.HttpContext.Session.Set(guid, Encoding.UTF8.GetBytes(json.ToStringEx()));

                        context.HttpContext.Response.Redirect(url);

                        context.HandleResponse();
                        
                    }
                }
            });

            services.AddSession();
        }

        

        public static void UseWechatOAuth(this IApplicationBuilder app )
        {
            app.UseSession();

            app.UseAuthentication();
            
            IRegisterService register = RegisterService.Start(new SenparcSetting(false) { }).UseSenparcGlobal();// 启动 CO2NET 全局注册，必须！

            register.UseSenparcWeixin(new SenparcWeixinSetting(false));//微信全局注册，必须！
        }

        public static void UseWechatPay(this IServiceCollection services, IWechatCache cache=null)
        {
            if (cache == null)
            {
                cache = new WechatDefaultCache();
            }

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();


            services.AddSingleton<IWechatCache>(cache);

            services.AddSingleton<IWechatPay>(WechatApi.Default.Pay);
        }



    }

    

    public interface IWechatCache
    {
        JObject Get(string key);

        void Set(string key, JObject value);

        void Set(string key, JObject value, TimeSpan expireTime);
    }

    public class WechatDefaultCache : IWechatCache
    {
        private MemoryCache _cache=new MemoryCache(new MemoryDistributedCacheOptions());


        public JObject Get(string key)
        {
            return (JObject) _cache.Get(key);
        }

        public void Set(string key, JObject value)
        {
            _cache.Set(key, value);
        }

        public void Set(string key, JObject value,TimeSpan expireTime)
        {
            _cache.Set(key, value,expireTime);
        }
    }
}
